package ie.lawlor.amvc;

import ie.lawlor.amvc.controller.Controller;
import ie.lawlor.amvc.event.Event;
import ie.lawlor.amvc.event.EventName;
import ie.lawlor.amvc.event.EventNotHandledException;
import ie.lawlor.amvc.event.IEventHandler;
import ie.lawlor.amvc.event.ReflectionEventHandler;

import org.apache.log4j.Logger;


/**
 * @author blawlor
 * This proxy does not implement the entire View interface - it 
 * is abstract. Concrete implementations should implement the 
 * difference.
 */
public abstract class ViewProxy implements IView {
  
  protected Logger logger = null;
  protected Controller controller;
  protected IEventHandler eventHandler;
  protected IEventHandler proxyHandler;
  protected IView view;
  protected boolean visible = false;
  protected String name;
  private String loggerName;
  
  public ViewProxy(String name, IView view) {
    this.view = view;
    this.name = name;
    initLogger(name);
    eventHandler = new ReflectionEventHandler(view, loggerName);
    proxyHandler = new ReflectionEventHandler(this, loggerName);
  }
  
  public ViewProxy(IView view) {
    this.view = view;
    this.name = "<noname>";
    initLogger(name);
    eventHandler = new ReflectionEventHandler(view, loggerName);
    proxyHandler = new ReflectionEventHandler(this, loggerName);
  }
  
  private void initLogger(String name){
    loggerName = "hmvc." + name + ".view";
    logger = Logger.getLogger(loggerName);
  }
  
  public Logger getLogger(){
    return logger;
  }
  
  
  public void setController(Controller controller) {
    this.controller = controller;
  }
  
  /**
   * @return Returns the controller.
   */
  public Controller getController() {
    return controller;
  }
  
  /**
   * @return
   */
  public boolean isVisible() {
    return visible;
  }
  
  /**
   * @param visible
   */
  public void setViewVisible(boolean visible) {
    this.visible = visible;
    if (controller != null){
      controller.visibilityUpdated(visible);
    }
  }
  
  /* (non-Javadoc)
   * @see com.informatica.amvc.EventSource#fire(com.informatica.amvc.Event)
   */
  public void fire(Event e) {
    logger.info("Firing " + e);
    e.setSourceController(controller);
    controller.eventIn(e);
  }
  
  /* (non-Javadoc)
   * @see com.informatica.amvc.EventSource#fire(com.informatica.amvc.Event)
   */
  public void fire(EventName name) {
    logger.info("Firing " + name);
    fire(name, null);
  }
  
  /* (non-Javadoc)
   * @see com.informatica.amvc.EventSource#fire(com.informatica.amvc.Event)
   */
  public void fire(EventName name, Object payload) {
    logger.info("Firing " + name);
    Event e = new Event(name, view, payload);
    e.setSourceController(controller);
    controller.eventIn(e);
  }
  
/**
 * Events are either handled by the view's event handler, or failing that, by the 
 * proxy's event handler.
 */
  public void eventIn(Event e){
    System.out.println("View for " + name + ": Handling event " + e);
    try {
      eventHandler.handleEvent(e);
    } catch (EventNotHandledException ex){
      try {
        proxyHandler.handleEvent(e);
      } catch (EventNotHandledException ex1){
        logger.warn("Event " + e +
                " not handled in view " + name);
      }
    }
  }
  
  /**
   * @return Returns the name.
   */
  public String getName() {
    return name;
  }
  /**
   * @param name The name to set.
   */
  public void setName(String name) {
    this.name = name;
  }
}
